package org.cos.verifier.automata;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.Vector;

import org.cos.verifier.automata.*;

import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

public class AutomataParser {
	private AutomataBuilder ab = null;
	private KXmlParser parser = null;
	private int state_counter = 0;
	private int crr_state_id = -1;
	private int crr_dst_state_id = -1;
	private int crr_method_id = -1;
	private int crr_cond_target_id = -1;
	private int crr_cond_type = -1;
	private String crr_cond_set_rel = null;
	private String crr_method_name = null;
	private Vector crr_params = null;
	private Vector crr_conditions = null;
	private Vector crr_actions = null;
	private Vector crr_cond_set_values = null;
	private Vector crr_cond_sets = null;
	private boolean crr_has_method = true;
	public String name=null;
	
	public AutomataParser(){
		reset();
	}
	
	public void reset(){
		state_counter = 0;
		crr_state_id = -1;
		crr_dst_state_id = -1;
		crr_method_id = -1;
		crr_cond_target_id = -1;
		crr_cond_type = -1;
		parser = new KXmlParser();
		ab = new AutomataBuilder();
		crr_method_name = new String("");
		crr_params = new Vector();
		crr_conditions = new Vector();
		crr_actions = new Vector();
		crr_cond_set_values = new Vector();
		crr_cond_sets = new Vector();
		ab.build_name(name);
	}
	
	public Automata parse(String xml_str){
		try {
			byte[] ss = xml_str.getBytes();
			parser.setInput(new InputStreamReader(
							new ByteArrayInputStream(ss)));
			int event_type = parser.getEventType();
			
			while (event_type != XmlPullParser.END_DOCUMENT) {
				// Enter Tag
				if (event_type == XmlPullParser.START_TAG) {
					//System.out.println("[Enter Tag `" + parser.getName() + "']");
					crack_tag_entry(parser.getName(), parser);
				} else if (event_type == XmlPullParser.END_TAG) {
					//System.out.println("[EXIT Tag `" + parser.getName() + "']");
					crack_tag_exit(parser.getName(), parser);
				}
				event_type = parser.next();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return null;
	}
	
	
	public void crack_tag_entry(String tagName, KXmlParser parser){
		if (tagName.equalsIgnoreCase("class")) {
			//System.out.println("Class");
			//enter_class();
		} else if (tagName.equalsIgnoreCase("state")){
			enter_state();
		} else if (tagName.equalsIgnoreCase("transition")){
			enter_transition();
		} else if (tagName.equalsIgnoreCase("method")){
			enter_method();
		} else if (tagName.equalsIgnoreCase("parameter")){
			enter_parameter();
		} else if (tagName.equalsIgnoreCase("condition")){
			enter_condition();
		} else if (tagName.equalsIgnoreCase("action")){
			enter_action();
		} 
		return;
	}
	

	public void crack_tag_exit(String tagName, KXmlParser parser){
		if (tagName.equalsIgnoreCase("transition")){
			exit_transition();
		} else if (tagName.equalsIgnoreCase("method")){
			exit_method();
		} else if (tagName.equalsIgnoreCase("parameter")){
			exit_parameter();
		} 
		return;
	}

	
	private void enter_condition() {
		crr_cond_sets = new Vector();
		Vector attrs = get_crr_attr();
		int target_id = -1;
		String type  = "";
		for (Enumeration enum_attr = attrs.elements(); enum_attr.hasMoreElements();) {
			Pair p = (Pair)enum_attr.nextElement();
			if (((String)p.head).equalsIgnoreCase("target")) {
				target_id = Integer.parseInt((String)p.tail);
			} else if(((String)p.head).equalsIgnoreCase("type")) {
				type = ((String)p.tail);
			}
		}
		int event_type = -1;
		Vector sets = new Vector();
		try {
			event_type = parser.next();
			while (event_type != XmlPullParser.END_DOCUMENT) {
				String tag_name = parser.getName(); 
				if ( event_type == XmlPullParser.TEXT ) {
					event_type = parser.next();
					continue;
				}
				if (tag_name.equalsIgnoreCase("condition")) {
					//System.out.println("[EXIT Tag `" + parser.getName() + "']");
					break;
				} 
				if (event_type == XmlPullParser.END_TAG ) {
					event_type = parser.next();
					continue;
				}
				if (tag_name.equalsIgnoreCase("set")){
					String set_relation = (String) ((Pair)get_crr_attr().elementAt(0)).tail;
					Vector values= new Vector();
					event_type = parser.next();
					while (event_type != XmlPullParser.END_DOCUMENT ) {
						while (parser.getName() == null ) {
							event_type = parser.next();
						}
						if (parser.getName().equalsIgnoreCase("set")) {
							break;
						}
						if (event_type == XmlPullParser.END_TAG){
							event_type = parser.next();
							continue;
						}
						if (parser.getName().equalsIgnoreCase("value")){
							String t = get_crr_text();
							values.addElement(t);
						}
						event_type = parser.next();
					}
					if (set_relation.equalsIgnoreCase("RANGE")){
						sets.addElement(new CondSet(set_relation, values.firstElement(), 
													values.lastElement()));
					} else {
						sets.addElement(new CondSet(set_relation, values.firstElement(), null));
					}
				} else {
					//System.out.println("@");
				}
				event_type = parser.next();
			}
		} catch (XmlPullParserException e) {
			e.printStackTrace();
		} catch (IOException e){
			e.printStackTrace();
		}
		this.crr_conditions.addElement(
			new Condition(type, target_id, sets));	
	}
	
	private void enter_action() {
		Vector attrs = get_crr_attr();
		String opt = null;
		String value = null;
		int target_id = -1;
		String type  = null;
		for (Enumeration enum_attr = attrs.elements(); enum_attr.hasMoreElements();) {
			Pair p = (Pair)enum_attr.nextElement();
			if (((String)p.head).equalsIgnoreCase("target")) {
				target_id = Integer.parseInt((String)p.tail);
			} else if(((String)p.head).equalsIgnoreCase("type")) {
				type = ((String)p.tail);
			}
		}
		int event_type = -1;
		try {
			event_type = parser.next();
			while (event_type != XmlPullParser.END_DOCUMENT) {
				String tag_name = parser.getName(); 
				if ( event_type == XmlPullParser.TEXT ) {
					event_type = parser.next();
					continue;
				}
				if (tag_name.equalsIgnoreCase("action")) {
					//System.out.println("[EXIT Tag `" + parser.getName() + "']");
					break;
				} 
				if (event_type == XmlPullParser.END_TAG ) {
					event_type = parser.next();
					continue;
				}
				if (tag_name.equalsIgnoreCase("operation")){
					opt = get_crr_text();
				} else if (tag_name.equalsIgnoreCase("value")){
					value = get_crr_text();
				}
				event_type = parser.next();
			}
		} catch (XmlPullParserException e) {
			e.printStackTrace();
		} catch (IOException e){
			e.printStackTrace();
		}
		this.crr_actions.addElement(new Action(type, target_id,  opt, value));	
	}

	public Vector get_crr_attr() {
		int c = parser.getAttributeCount();
		Vector v = new Vector();
		if (c > 0) {
			for (int i = 0; i < c; i++) {
				v.addElement(new Pair(parser.getAttributeName(i), 
							parser.getAttributeValue(i)));
			}
		}
		return v;
	}
	
	public String get_crr_text(){
		try {
			if (parser.next() == XmlPullParser.TEXT) {
				return parser.getText();			
			}
			 
		} catch (XmlPullParserException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}		
		return  null;
	}
	
	private void enter_parameter() {
		crr_params.addElement(((Pair)get_crr_attr().elementAt(0)).tail);	
	}
	
	private void exit_parameter() {
		;
	}	
	
	private void enter_method() {
		//create a new parameters type list
		crr_params = new Vector();
		//and set current method name
		Vector attrs = get_crr_attr();
		Pair p = (Pair) attrs.elementAt(0);
		crr_method_name = new String((String) p.tail);
		crr_method_id += 1;
		crr_has_method = true;
	}

	private void exit_method(){
		//ab.set_method( crr_method_name, crr_params);
	}


	private void enter_state() {
		boolean is_init = state_counter == 0 ? true: false;
		Vector attrs = get_crr_attr();
		boolean is_final = false;
		for (Enumeration enum_attr = attrs.elements(); enum_attr.hasMoreElements();) {
			Pair p = (Pair)enum_attr.nextElement();
			if (((String)p.head).equalsIgnoreCase("id")) {
				crr_state_id = Integer.parseInt((String)p.tail);
			} else if(((String)p.head).equalsIgnoreCase("isAccepted")) {
				is_final = ((String)p.tail).equalsIgnoreCase("TRUE");
			}
		}
		//State new_state = new State(state_counter); 
		
		ab.set_state(crr_state_id, is_init, is_final);
		state_counter += 1;
	}
	
	private void enter_transition() {
		crr_has_method = false;
		crr_method_name = "";
		crr_params = new Vector();
		crr_conditions = new Vector();
		crr_actions = new Vector();
		crr_dst_state_id = Integer.parseInt((String)((Pair)get_crr_attr().lastElement()).tail);
		
	}
	
	private void exit_transition() {
		Method method = new Method(crr_method_name, crr_params);
		ab.build_transition(crr_state_id, crr_dst_state_id, method, crr_conditions, crr_actions);
	}

	
	public void recognise_method() {
		;
	}
	
	public void recognise_condition() {
		;
	}
	
	public void recognise_action() {
		;
	}
	public Automata get_automata(){
		Automata am = ab.get_automata();
		reset();
		return am;
	}
	
}
